package com.pro.framework.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.pro.framework.EnumProperties;
import com.pro.framework.api.entity.IEntityProperties;
import com.pro.framework.api.enums.*;
import com.pro.framework.api.util.*;
import com.pro.framework.core.EnumBeanUtil;
import com.pro.framework.core.EnumConstant;
import com.pro.framework.core.EnumUtil;
import com.pro.framework.jdbc.service.IBaseService;
import com.pro.framework.model.dto.EnumData;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 枚举入库服务
 */
@SuppressWarnings({"deprecation", "rawtypes", "unchecked"})
@Slf4j
@AllArgsConstructor
public class EnumsExecuteService implements IEnumsService {

    private IBaseService dbBaseService;
    private EnumProperties enumProperties;
    private IEntityProperties entityProperties;

    /**
     * 枚举入库
     */
    @Override
    public List<String> getTranslateKeys(boolean isCommon, String platform) {
        String packageCommon = "com.pro." + "common";
        String packageFramework = "com.pro." + "framework";
        EnumConstant.load(enumProperties);
        Class<IEnumToDbEnum> intf = IEnumToDbEnum.class;
        List<Class> enumClasses = EnumConstant.simpleNameClassMapNoReplace.values().stream()
                .filter(intf::isAssignableFrom)
                .filter(c -> isCommon == (c.getPackage().getName().startsWith(packageCommon) || c.getPackage()
                        .getName()
                        .startsWith(packageFramework)))
                .sorted(Comparator.comparing(
                        c -> null == c.getAnnotation(EnumOrder.class) ? 100 : c.getAnnotation(EnumOrder.class).value()))
                .collect(Collectors.toList());
        return enumClasses.stream().flatMap(c -> {
            List<Enum> enums = EnumUtil.enumList(c);
            return enums.stream().flatMap(e -> {
                Map<String, Object> map = EnumUtil.toMap(e);
                String title = (String) map.get("title");
                String label = (String) map.get("label");
                String remark = (String) map.get("remark");
                String description = (String) map.get("description");
                String name = (String) map.get("name");
                return Stream.of(title, label, name, remark, description);
            });
        }).distinct().toList();
    }

    /**
     * 枚举入库
     */
    @Override
    public void executeSql() {
        EnumConstant.load(enumProperties);
        Class<IEnumToDbEnum> intf = IEnumToDbEnum.class;
        List<Class> enumClasses = EnumConstant.simpleNameClassMapNoReplace.values()
                .stream()
                .filter(intf::isAssignableFrom)
                .sorted(Comparator.comparing(
                        c -> null == c.getAnnotation(EnumOrder.class) ? 100 : c.getAnnotation(EnumOrder.class).value()))
                .collect(Collectors.toList());

        Map<Class, Class> entityClassEntityClassMapInIntf = enumClasses.stream()
                .map(c -> new AbstractMap.SimpleEntry<>(c, getGeneClass(c, intf)))
                .filter(entry -> entry.getValue() != null)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v1, LinkedHashMap::new));

        Map<Class, Class> entityClassEntityClassMapInConfig = enumProperties.getEnumClasses().stream()
                .collect(Collectors.toMap(c -> c, c -> {
                            Class<?> entityClass = EnumsExecuteService.getEntityClass(c);
                            AssertUtil.notEmpty(entityClass, "关联的实体类不存在 枚举类: " + c);
                            return entityClass;
                        }, (v1, v2) -> v1,
                        LinkedHashMap::new));

        Map<Class, Class> entityClassEntityClassMap = new LinkedHashMap<>();
        entityClassEntityClassMap.putAll(entityClassEntityClassMapInIntf);
        entityClassEntityClassMap.putAll(entityClassEntityClassMapInConfig);
        entityClassEntityClassMap.forEach((enumClass, entityClass) -> {
            // 读取枚举实例,入库
            try {
                // 获取一个子类在实现接口使用的,泛型类
//                Class entityClass = getGeneClass(enumClass, intf);
                if (entityClass == null) {
                    return;
                }
                if (enumClass.getSimpleName().equals("EnumAuthRouteBaoyiGoodsCollect")) {
                    int i = 0;
                }
                // 定制类
                entityClass = entityProperties.getEntityClassReplaceMap()
                        .getOrDefault(StrUtils.firstToLowerCase(entityClass.getSimpleName()), entityClass);
                AssertUtil.isTrue(IEnumToDbDb.class.isAssignableFrom(entityClass), "_必须实现IEnumToDbDb",
                        entityClass.getSimpleName());

                readEnumInstancesSaveOrUpdate(dbBaseService, enumClass, entityClass);
            } catch (Exception e) {
                log.error("枚举入库完成 存在异常 {}", enumClass, e);
            }
        });
        log.info("枚举入库完成 扫描了: {}",
                entityClassEntityClassMap.keySet().stream().map(Class::getSimpleName).collect(Collectors.joining(",")));
    }

    @Override
    public Class<? extends Enum> getEnumClass(String simpleClassName) {
        return EnumConstant.simpleNameClassMap.get(simpleClassName);
    }

    @Override
    public List<Map<String, Object>> getFullList(Class<? extends Enum> eClass) {
        return EnumUtil.getFullList(eClass);
    }

    @Override
    public List<Map<String, Object>> getSimpleList(Class<? extends Enum> eClass) {
        return EnumUtil.getSimpleList(eClass);
    }

    /**
     * 读取枚举中的所有枚举实例,并保存
     */
    @SneakyThrows
    private <ENUM extends Enum<?> & IEnumToDbEnum<ENTITY>, ENTITY extends IEnumToDbDb> void readEnumInstancesSaveOrUpdate(IBaseService<ENTITY> dbBaseService, Class<ENUM> enumClass, Class<ENTITY> entityClass) {
        LocalDateTime now = LocalDateTime.now();
        // 读取枚举
        List<EnumData<ENTITY>> enumDatas = readEnumInstances(enumClass, entityClass);
        // 查询旧数据
        List<ENTITY> oldEntitys = dbBaseService.getList(entityClass.newInstance());

//        log.warn("oldEntitys={}", JSONUtil.toJsonStr(oldEntitys));
        Map<String, ENTITY> oldMap = CollUtils.listToMap(oldEntitys, ENTITY::getToDbCode);
        Set<String> oldCodes = oldMap.keySet();

//        boolean banner = entityClass.getSimpleName().equals("AuthDict");
//        if (banner) {
//            int i = 0;
//        }
        if (enumClass.getSimpleName().equals("EnumAuthRouteBaoyiGoodsCollect")) {
            int i = 0;
            String toDbCode = enumDatas.get(1).getToDbCode();
            System.out.println("toDbCode " + toDbCode);
        }
        // 新增
        List<ENTITY> creates = enumDatas.stream()
                .filter(enumData -> !oldCodes.contains(enumData.getToDbCode()))
                .peek(enumData -> enumData.getEntity().setToDbCode(enumData.getToDbCode()))
                .map(EnumData::getEntity)
                .collect(Collectors.toList());
        if (!creates.isEmpty()) {
            log.warn("自动保存数据| {} {}", enumClass.getSimpleName(), JSONUtil.toJsonStr(creates));
        }
        dbBaseService.saveBatch(creates);
        // 更新
        List<ENTITY> updates = enumDatas.stream().filter(enumData -> {
            String code = enumData.getToDbCode();
            ENTITY oldEntity = oldMap.get(code);
            LocalDateTime forceTime = LogicUtils.and(enumData.getForceChangeTime(), DateUtil::parseLocalDateTime);
            LocalDateTime oldUpdateTime = null == oldEntity ? null : oldEntity.getUpdateTime();
            boolean doUpdate = oldCodes.contains(
                    code) && null != forceTime && null != oldUpdateTime && !forceTime.isBefore(oldUpdateTime);
            if (doUpdate) {
                // 回填id
                ENTITY entity = enumData.getEntity();
                entity.setId(oldEntity.getId());
                entity.setUpdateTime(now);
            }
            return doUpdate;
        }).map(EnumData::getEntity).collect(Collectors.toList());
        dbBaseService.updateBatchById(updates);
        if (!creates.isEmpty()) {
            log.info("枚举入库 {} 新增:{} {}", enumClass, creates.size(),
                    creates.stream().map(ENTITY::getToDbCode).collect(Collectors.joining(",")));
        }
        if (!updates.isEmpty()) {
            log.info("枚举入库 {} 修改:{} {}", enumClass, updates.size(),
                    updates.stream().map(ENTITY::getToDbCode).collect(Collectors.joining(",")));
        }
//        enumDatas.stream().filter(e->e.getEnumToDbCode().contains("count")).findAny().ifPresent(enumData -> {
//            log.info("枚举入库 count {}", enumClass);
//        });
        int i = 0;
    }

    /**
     * 读取枚举中的所有枚举实例
     */
    public static <ENUM extends Enum<?> & IEnumToDbEnum<ENTITY>, ENTITY extends IEnumToDbDb> List<EnumData<ENTITY>> readEnumInstances(Class<ENUM> enumClass, Class<ENTITY> entityClass) {
        return Arrays.stream(enumClass.getEnumConstants())
                .map(e -> EnumsExecuteService.readEnumInstance(e, entityClass))
                .collect(Collectors.toList());
    }

    /**
     * 读取枚举实例
     */
    @SneakyThrows
    private static <ENUM extends Enum<?> & IEnumToDbEnum<ENTITY>, ENTITY extends IEnumToDbDb> EnumData<ENTITY> readEnumInstance(ENUM enumInstance, Class<ENTITY> entityClass) {
        // 创建实体对象
        ENTITY entity = entityClass.newInstance();

        // 获取枚举值的所有字段
//        Field[] fields = enumInstance.getClass().getDeclaredFields();
//        for (Field field : fields) {
//            if (!field.canAccess(entity)) {
//                field.setAccessible(true);
//            }
//            Object value = field.get(enumInstance);
//            Field entityField = entityClass.getDeclaredField(field.getName());
//            entityField.setAccessible(true);
//            entityField.set(entity, value);
//        }
//        if (enumInstance.getCode().equals("baoyi_goodsLaunchTemu")) {
//            int i = 0;
//        }
        BeanUtil.copyProperties(enumInstance, entity);
        String toDbCode = enumInstance.getToDbCode();

        entity.setToDbCode(toDbCode);
        return new EnumData<>(entity, toDbCode, enumInstance.getForceChangeTime());
    }

    @SneakyThrows
    public static Class<?> getGeneClass(Class<?> childClass, Class<?> targetInterface) {
        // 先检查直接实现的接口
        for (Type genericInterface : childClass.getGenericInterfaces()) {
            Class<?> result = resolveType(genericInterface, targetInterface);
            if (result != null) {
                return result;
            }
        }

        // 如果没找到，递归检查父类（枚举/类可能有继承）
        Class<?> superclass = childClass.getSuperclass();
        if (superclass != null && !Object.class.equals(superclass)) {
            return getGeneClass(superclass, targetInterface);
        }

        return null;
    }

    private static Class<?> resolveType(Type type, Class<?> targetInterface) {
        if (type instanceof ParameterizedType parameterizedType) {
            Type rawType = parameterizedType.getRawType();
            if (rawType.equals(targetInterface)) {
                // 找到目标接口，返回泛型参数
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                if (actualTypeArguments.length > 0 && actualTypeArguments[0] instanceof Class) {
                    return (Class<?>) actualTypeArguments[0];
                }
            }
            // 如果没匹配到目标接口，递归检查父接口
            if (rawType instanceof Class<?> clazz) {
                for (Type superIfc : clazz.getGenericInterfaces()) {
                    Class<?> result = resolveType(superIfc, targetInterface);
                    if (result != null) {
                        return result;
                    }
                }
            }
        } else if (type instanceof Class<?> clazz) {
            // 普通接口（比如 IEnumToDbEnumAuthRoute）
            for (Type superIfc : clazz.getGenericInterfaces()) {
                Class<?> result = resolveType(superIfc, targetInterface);
                if (result != null) {
                    return result;
                }
            }
        }
        return null;
    }


    /**
     * 获取一个子类在实现接口使用的,泛型类
     */
    @SneakyThrows
    public static Class<?> getEntityClass(Class<?> chlidClass) {
        EnumToDbEnum annotation = chlidClass.getAnnotation(EnumToDbEnum.class);
        if (annotation != null) {
            Class<?> aClass = null;
            try {
                aClass = Class.forName(annotation.entityClass());
            } catch (ClassNotFoundException e) {
                String entityClass = annotation.entityClass();
                if (entityClass.isEmpty()) {
                    throw e;
                } else {
                    log.debug("当前模块不存在 {} 这个实体类,跳过入库", entityClass);
                }
            }
            return aClass;
        }
        throw new IllegalArgumentException("Unable to determine generic type.");
    }

    @Override
    public void reload() {
        executeSql();
    }
}
